/*******************************************************************

    Author: Xiao
    Date: 2022/3/29 17:24

*******************************************************************/

package controller

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"mcr/pkg/config"
	"mcr/pkg/dao"
	"mcr/pkg/logs"
	"mcr/pkg/middleware"
	"mcr/pkg/utils"
	socket "mcr/pkg/websocket"
	"strconv"
	"strings"
	"time"
)

type RoomCreatReq struct {
	BasicReq
	RoomName   string `json:"room_name" binding:"required"`
	RoomType   int    `json:"room_type" binding:"required"`
	RoomNotice string `json:"room_notice"`
}

// 创建房间
func CreateRoom(ctx *gin.Context) {
	rcr := RoomCreatReq{}
	err := ctx.ShouldBindJSON(&rcr)
	if err != nil {
		logs.Log.Errorf("获取用户请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if rcr.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(rcr.AccessToken)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  err,
		})
		return
	}
	_, err = dao.GetCacheString(fmt.Sprintf("create_room_user_%d", uid))
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "你暂时没有创建房间权限，申请权限请联系管理员",
		})
		return
	}
	if _, err = dao.GetRoomByUserId(uid); err == nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "创建失败,你已经有了一个房间",
		})
		return
	}
	r := dao.Room{
		RoomUser:   uid,
		RoomName:   rcr.RoomName,
		RoomNotice: rcr.RoomNotice,
		RoomType:   rcr.RoomType,
	}
	nr, err := dao.CreateRoom(r)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "创建失败,请重试",
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    200,
		"msg":     "你的私人房间创建成功!",
		"room_id": nr.RoomId,
	})
	return
}

type RoomUpdateReq struct {
	BasicReq
	dao.Room
}

// 更新房间配置
func UpdateRoomSetting(ctx *gin.Context) {
	rur := RoomUpdateReq{}
	err := ctx.ShouldBindJSON(&rur)
	if err != nil {
		logs.Log.Errorf("获取用户请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if rur.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	r, err := dao.GetRoomById(rur.RoomId)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "数据查询失败",
		})
		return
	}
	uid, err := middleware.GetUserId(rur.AccessToken)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  err,
		})
		return
	}
	u, err := GetUserData(uid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取操作用户失败",
		})
		return
	}
	if r.RoomUser != uid && !utils.GetIsAdmin(u.UserGroup) {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "你没有权限修改此房间信息",
		})
		return
	}

	ur := make(map[string]interface{})
	var reConnect uint8
	ur["room_public"] = rur.RoomPublic
	if rur.RoomPublic == 0 {
		ur["room_password"] = ""
	} else {
		if r.RoomPassword == "" {
			if rur.RoomPassword == "" {
				ctx.JSON(200, gin.H{
					"code": 500,
					"msg":  "请输入一个房间密码",
				})
				return
			} else {
				ur["room_password"] = rur.RoomPassword
				reConnect = 1
			}
		} else {
			if rur.RoomPassword != "" {
				ur["room_password"] = rur.RoomPassword
				reConnect = 1
			}
		}
		if reConnect == 1 && (len(rur.RoomPassword) < 4 || len(rur.RoomPassword) > 16) {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "密码长度应为4-16位",
			})
			return
		}
	}
	if rur.RoomType != 0 && rur.RoomType != 1 && rur.RoomType != 4 {
		ur["room_type"] = 1
	} else {
		ur["room_type"] = rur.RoomType
	}
	if rur.RoomAddsongcd < 60 && rur.RoomAddsongcd > 0 {
		ur["room_addsongcd"] = rur.RoomAddsongcd
	}
	if rur.RoomPushsongcd > 0 {
		ur["room_pushsongcd"] = rur.RoomPushsongcd
	} else {
		ur["room_pushsongcd"] = 60
	}
	if rur.RoomPushdaycount >= 0 {
		ur["room_pushdaycount"] = rur.RoomPushdaycount
	} else {
		ur["room_pushdaycount"] = 5
	}
	if rur.RoomAddcount > 0 {
		ur["room_addcount"] = rur.RoomAddcount
	} else {
		ur["room_addcount"] = 5
	}
	if rur.RoomBackground != "" {
		ur["room_background"] = rur.RoomBackground
		if !strings.Contains(strings.ToLower(rur.RoomBackground), ".jpg") && !strings.Contains(strings.ToLower(rur.RoomBackground), ".jpeg") && !strings.Contains(strings.ToLower(rur.RoomBackground), ".png") {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "房间背景支持JPG/PNG图片",
			})
			return
		}
	}
	ur["room_name"] = rur.RoomName
	ur["room_notice"] = rur.RoomNotice
	ur["room_hide"] = rur.RoomHide
	ur["room_robot"] = rur.RoomRobot
	ur["room_addsong"] = rur.RoomAddsong
	ur["room_sendmsg"] = rur.RoomSendmsg
	ur["room_votepass"] = rur.RoomVotepass
	ur["room_votepercent"] = rur.RoomVotepercent
	ur["room_votepass"] = rur.RoomVotepercent
	ur["room_fullpage"] = rur.RoomFullpage
	err = dao.UpdateRoom(rur.RoomId, ur)
	if err != nil {
		logs.Log.Errorf("房间信息修改失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "房间信息修改失败",
		})
	}
	// 保存信息
	sendMsg := make(map[string]interface{})
	sendMsg["type"] = "roomUpdate"
	sendMsg["reConnect"] = reConnect
	sendMsg["user"] = u
	socket.SendMsgToRoom(rur.RoomId, sendMsg)
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "房间信息修改成功",
	})
	return
}

type RoomInfoReq struct {
	BasicReq
	RoomId       string `json:"room_id" binding:"required"`
	RoomPassword string `json:"room_password"`
}

// 获取房间信息
func GetRoomInfo(ctx *gin.Context) {
	rir := RoomInfoReq{}
	err := ctx.ShouldBindJSON(&rir)
	if err != nil {
		logs.Log.Errorf("获取用户请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	rid, err := strconv.Atoi(rir.RoomId)
	if err != nil {
		logs.Log.Errorf("转换房间ID:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	r, err := dao.GetRoomById(rid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 404,
			"msg":  "没有查询到数据",
		})
		return
	}
	if r.RoomStatus == 1 {
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  r.RoomReason,
		})
		return
	}
	if rir.AccessToken == config.ConfigValue.GuestToken {
		if r.RoomPublic == 1 {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "暂不支持游客进入密码房间",
			})
			return
		}
		r.RoomPassword = ""
		u, err := dao.GetUserByUserId(r.RoomUser)
		if err != nil {
			r.Admin = false
		} else {
			ui := UserInfo{
				UserId:       u.UserId,
				UserTouchtip: u.UserTouchtip,
				UserSex:      u.UserSex,
				UserRemark:   u.UserRemark,
				UserHead:     u.UserHead,
				UserName:     u.UserName,
				UserDevice:   u.UserDevice,
				UserExtra:    u.UserExtra,
				UserIcon:     u.UserIcon,
				UserVip:      u.UserVip,
				UserAdmin:    utils.GetIsAdmin(u.UserGroup),
				MyRoom:       false,
			}
			r.Admin = ui
		}
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "数据加载成功",
			"data": r,
		})
		return
	}
	uid, err := middleware.GetUserId(rir.AccessToken)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  err,
		})
		return
	}
	if r.RoomPublic == 1 && r.RoomUser != uid && uid > 100 {
		cashRomePasswordName := fmt.Sprintf("password_room_%d_password_%d", r.RoomId, uid)
		savedPassword, err := dao.GetCacheString(cashRomePasswordName)
		if err != nil {
			savedPassword = ""
		}
		if savedPassword != r.RoomPassword && rir.RoomPassword != r.RoomPassword {
			ctx.JSON(200, gin.H{
				"code": 302,
				"msg":  "房间密码错误，进入房间失败",
			})
			return
		}
		err = dao.SetCacheString(cashRomePasswordName, r.RoomPassword, 86400*time.Second)
		if err != nil {
			logs.Log.Errorf("设置房间密码缓存失败:%s", err)
		}
	}
	r.RoomPassword = ""
	u, err := dao.GetUserByUserId(r.RoomUser)
	if err != nil {
		r.Admin = false
	} else {
		ui := UserInfo{
			UserId:       u.UserId,
			UserTouchtip: u.UserTouchtip,
			UserSex:      u.UserSex,
			UserRemark:   u.UserRemark,
			UserHead:     u.UserHead,
			UserName:     u.UserName,
			UserDevice:   u.UserDevice,
			UserExtra:    u.UserExtra,
			UserIcon:     u.UserIcon,
			UserVip:      u.UserVip,
			UserAdmin:    utils.GetIsAdmin(u.UserGroup),
			MyRoom:       false,
		}
		r.Admin = ui
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "数据加载成功",
		"data": r,
	})
	return
}

// 获取我的房间
func GetMyRoom(ctx *gin.Context) {
	br := BasicReq{}
	err := ctx.ShouldBindJSON(&br)
	if err != nil {
		logs.Log.Errorf("获取用户请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	if br.AccessToken == config.ConfigValue.GuestToken {
		ctx.JSON(200, gin.H{
			"code": 401,
			"msg":  "请登录后体验完整功能!",
		})
		return
	}
	uid, err := middleware.GetUserId(br.AccessToken)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  err,
		})
		return
	}
	r, err := dao.GetRoomByUserId(uid)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "获取成功",
		})
		return
	}
	r.RoomPassword = ""
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "获取成功",
		"data": r,
	})
	return
}

type WebsocketUrlReq struct {
	BasicReq
	Channel      int    `json:"channel" binding:"required"`
	RoomPassword string `json:"room_password"`
}

// 获取websocket地址
func GetWebsocketUrl(ctx *gin.Context) {
	wur := WebsocketUrlReq{}
	err := ctx.ShouldBindJSON(&wur)
	if err != nil {
		logs.Log.Errorf("获取用户请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	r, err := dao.GetRoomById(wur.Channel)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 404,
			"msg":  "没有查询到数据",
		})
		return
	}
	ip := ctx.Request.RemoteAddr

	where, err := dao.GetCacheString("ip_addr_" + ip)
	if err != nil || where == "" {
		where = utils.GetAddrPath(ip)
		err = dao.SetCacheString("ip_addr_"+ip, where, 3600*time.Second)
		if err != nil {
			logs.Log.Errorf("存储IP缓存失败:%s", err)
		}
	}
	if wur.AccessToken == config.ConfigValue.GuestToken {
		if r.RoomPublic == 1 {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "静止游客进入密码房间",
			})
			return
		}
		lastSend, err := dao.GetCacheString("channel_" + strconv.Itoa(wur.Channel) + "_user_" + ip)
		if err != nil || lastSend == "" {
			content := "欢迎"
			if where != "" {
				content += "来自" + where + "的"
			}
			if wur.Plat != "" {
				content += wur.Plat + "用户"
			} else {
				content += "临时用户"
			}
			msg := make(map[string]interface{})
			msg["type"] = "join"
			msg["name"] = "临时用户"
			msg["where"] = where
			msg["plat"] = wur.Plat
			msg["content"] = content
			// 发送信息到房间
			socket.SendMsgToRoom(wur.Channel, msg)
			err = dao.SetCacheString("channel_"+strconv.Itoa(wur.Channel)+"_user_"+ip, time.Now().Nanosecond(), 30*time.Second)
			if err != nil {
				logs.Log.Errorf("存储IP缓存失败:%s", err)
			}
		}
		data := make(map[string]interface{})
		data["account"] = ip
		data["channel"] = wur.Channel
		data["ticket"] = utils.GetWebsocketTicket(ip, wur.Channel)
		ctx.JSON(200, gin.H{
			"code": 200,
			"data": data,
			//"account": ip,
			//"channel": wur.Channel,
			//"ticket":  utils.GetWebsocketTicket(ip, wur.Channel),
		})
		return
	}
	uid, err := middleware.GetUserId(wur.AccessToken)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  err,
		})
		return
	}
	user, err := GetUserData(uid)
	if r.RoomPublic == 1 && r.RoomUser != uid && uid > 100 {
		cashRomePasswordName := fmt.Sprintf("password_room_%d_password_%d", r.RoomId, uid)
		savedPassword, err := dao.GetCacheString(cashRomePasswordName)
		if err != nil {
			savedPassword = ""
		}
		if savedPassword != r.RoomPassword && wur.RoomPassword != r.RoomPassword {
			ctx.JSON(200, gin.H{
				"code": 500,
				"msg":  "房间密码错误，获取服务器地址失败",
			})
			return
		}
		err = dao.SetCacheString(cashRomePasswordName, r.RoomPassword, 86400*time.Second)
		if err != nil {
			logs.Log.Errorf("设置房间密码缓存失败:%s", err)
		}
	}
	msg := make(map[string]interface{})
	lastSend, err := dao.GetCacheString("channel_" + strconv.Itoa(wur.Channel) + "_user_" + strconv.Itoa(uid))
	if err != nil || lastSend == "" {
		content := "欢迎"
		if where != "" {
			content += "来自" + where + "的"
		}
		content += user.UserName + "回来！"

		msg["type"] = "join"
		msg["name"] = user.UserName
		msg["where"] = where
		msg["plat"] = wur.Plat
		msg["content"] = content
		msg["user"] = user
		// 发送信息到房间
		socket.SendMsgToRoom(wur.Channel, msg)
		err = dao.SetCacheString("channel_"+strconv.Itoa(wur.Channel)+"_user_"+strconv.Itoa(uid), time.Now().Nanosecond(), 30*time.Second)
		if err != nil {
			logs.Log.Errorf("存储IP缓存失败:%s", err)
		}
	}
	data := make(map[string]interface{})
	data["account"] = user.UserId
	data["channel"] = wur.Channel
	data["ticket"] = utils.GetWebsocketTicket(strconv.Itoa(user.UserId), wur.Channel)
	ctx.JSON(200, gin.H{
		"code": 200,
		"data": data,
		//"account": user.UserId,
		//"channel": wur.Channel,
		//"ticket":  utils.GetWebsocketTicket(strconv.Itoa(user.UserId), wur.Channel),
	})
	return
}

// 获取热门房间
func GetHotRooms(ctx *gin.Context) {
	var br BasicReq
	err := ctx.ShouldBindJSON(&br)
	if err != nil {
		logs.Log.Errorf("获取用户请求参数失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 400,
			"msg":  "参数不合法",
		})
		return
	}
	list, err := dao.GetCacheString("room_list")
	if err == nil {
		var hrs []dao.HostRoom
		err := json.Unmarshal([]byte(list), &hrs)
		if err != nil {
			logs.Log.Errorf("解序列化游客热门房间的缓存失败:%s", err)

		}
		ctx.JSON(200, gin.H{
			"code": 200,
			"msg":  "缓存数据",
			"data": hrs,
		})
		return
	}
	rs, err := dao.GetHotRooms()
	if err != nil {
		logs.Log.Errorf("获取热门房间失败:%s", err)
		ctx.JSON(200, gin.H{
			"code": 500,
			"msg":  "获取热门房间失败",
		})
		return
	}
	for i := 0; i < len(rs); i++ {
		rs[i].UserAdmin = utils.GetIsAdmin(rs[i].UserGroup)
		rs[i].RoomPassword = ""
	}
	rsByte, err := json.Marshal(rs)
	if err != nil {
		logs.Log.Errorf("序列化游客热门房间的缓存失败:%s", err)
	}
	err = dao.SetCacheString("room_list", string(rsByte), 30*time.Second)
	if err != nil {
		logs.Log.Errorf("设置游客热门房间的缓存失败:%s", err)
	}
	ctx.JSON(200, gin.H{
		"code": 200,
		"msg":  "数据获取成功",
		"data": rs,
	})
	return
}
